package com.evolved.automata.experimental.tools;
import java.util.*;

public class BlobInfo {
	Dimension m_BlobCentroid;
	int m_PixelCount;
	HashSet<Integer> m_PointSet;
	Vector<Integer> m_ListOfLinearPoints;
	Vector<Dimension> m_ListOfDimensionPoints;
	int m_WidthTotal;
	int m_HeightTotal;
	Dimension m_BlobDimension;
	Dimension m_BottomLeft;
	Dimension m_TopRight;
	
	public static String m_LispFormat;

	
	public BlobInfo(Dimension initialPoint, int m_Width, int m_Height)
	{
		m_WidthTotal=m_Width;
		m_HeightTotal=m_Height;
		
		m_PixelCount=1;
		m_PointSet = new HashSet();
		int mappedCoord=BasicTools.MapCoord(initialPoint.width, initialPoint.height, m_Width);
		m_PointSet.add(mappedCoord);
		m_ListOfLinearPoints= new Vector();
		m_ListOfDimensionPoints=new Vector();
		m_ListOfLinearPoints.add(mappedCoord);
		m_ListOfDimensionPoints.add(initialPoint);
		m_BlobDimension= new Dimension(1,1);
		m_BottomLeft= new Dimension(initialPoint.width,initialPoint.height);
		m_TopRight= new Dimension(initialPoint.width,initialPoint.height);
		m_BlobCentroid=initialPoint;
	}
	
	public BlobInfo()
	{
		
	}
	
	
	
	public void addPoint(Dimension d)
	{
		int linearIndex=1*(d.width+d.height*m_WidthTotal);
		if (!m_PointSet.contains(linearIndex))
		{
			m_PointSet.add(linearIndex);
			m_ListOfLinearPoints.add(linearIndex);
			m_ListOfDimensionPoints.add(d);
			m_BlobCentroid=new Dimension((int)(1.0*m_BlobCentroid.width*m_PixelCount+d.width)/(m_PixelCount+1),(int)(1.0*m_BlobCentroid.height*m_PixelCount+d.height)/(m_PixelCount+1));
			m_PixelCount++;
			m_BottomLeft=new Dimension(Math.min(m_BottomLeft.width, d.width),Math.min(m_BottomLeft.height, d.height));
			m_TopRight=new Dimension(Math.max(m_BottomLeft.width, d.width),Math.max(m_BottomLeft.height, d.height));
			m_BlobDimension=new Dimension(m_TopRight.width-m_BottomLeft.width,m_TopRight.height-m_BottomLeft.height);
		}
	}
	
	public void add(Dimension d)
	{
		int linearIndex=1*(d.width+d.height*m_WidthTotal);
		if (!m_PointSet.contains(linearIndex))
		{
			m_PointSet.add(linearIndex);
			m_ListOfLinearPoints.add(linearIndex);
			m_ListOfDimensionPoints.add(d);
			m_BlobCentroid=new Dimension((int)(1.0*m_BlobCentroid.width*m_PixelCount+d.width)/(m_PixelCount+1),(int)(1.0*m_BlobCentroid.height*m_PixelCount+d.height)/(m_PixelCount+1));
			m_PixelCount++;
			m_BottomLeft=new Dimension(Math.min(m_BottomLeft.width, d.width),Math.min(m_BottomLeft.height, d.height));
			m_TopRight=new Dimension(Math.max(m_TopRight.width, d.width),Math.max(m_TopRight.height, d.height));
			m_BlobDimension=new Dimension(m_TopRight.width-m_BottomLeft.width,m_TopRight.height-m_BottomLeft.height);
		}
	}
	
	public void add(int linearPoint)
	{
		Dimension d = new Dimension(linearPoint % m_WidthTotal,linearPoint/m_WidthTotal);
		if (!m_PointSet.contains(linearPoint))
		{
			m_PointSet.add(linearPoint);
			m_ListOfLinearPoints.add(linearPoint);
			m_ListOfDimensionPoints.add(d);
			m_BlobCentroid=new Dimension((int)(1.0*m_BlobCentroid.width*m_PixelCount+d.width)/(m_PixelCount+1),(int)(1.0*m_BlobCentroid.height*m_PixelCount+d.height)/(m_PixelCount+1));
			m_PixelCount++;
			m_BottomLeft=new Dimension(Math.min(m_BottomLeft.width, d.width),Math.min(m_BottomLeft.height, d.height));
			m_TopRight=new Dimension(Math.max(m_TopRight.width, d.width),Math.max(m_TopRight.height, d.height));
			m_BlobDimension=new Dimension(m_TopRight.width-m_BottomLeft.width,m_TopRight.height-m_BottomLeft.height);
		}
	}
	
	public void addPoint(int linearPoint)
	{
		Dimension d = new Dimension(linearPoint % m_WidthTotal,linearPoint/m_WidthTotal);
		if (!m_PointSet.contains(linearPoint))
		{
			m_PointSet.add(linearPoint);
			m_ListOfLinearPoints.add(linearPoint);
			m_ListOfDimensionPoints.add(d);
			m_BlobCentroid=new Dimension((int)(1.0*m_BlobCentroid.width*m_PixelCount+d.width)/(m_PixelCount+1),(int)(1.0*m_BlobCentroid.height*m_PixelCount+d.height)/(m_PixelCount+1));
			m_PixelCount++;
			m_BottomLeft=new Dimension(Math.min(m_BottomLeft.width, d.width),Math.min(m_BottomLeft.height, d.height));
			m_TopRight=new Dimension(Math.max(m_BottomLeft.width, d.width),Math.max(m_BottomLeft.height, d.height));
			m_BlobDimension=new Dimension(m_TopRight.width-m_BottomLeft.width,m_TopRight.height-m_BottomLeft.height);
		}
	}
	
	
	public double distance(BlobInfo b)
	{
		//int dx=(m_BlobCentroid.width-b.m_BlobCentroid.width)*(m_BlobCentroid.width-b.m_BlobCentroid.width);
		//int dy=(m_BlobCentroid.height-b.m_BlobCentroid.height)*(m_BlobCentroid.height-b.m_BlobCentroid.height);
		return Math.sqrt(
				(m_BlobCentroid.width-b.m_BlobCentroid.width)*(m_BlobCentroid.width-b.m_BlobCentroid.width)
				+
				(m_BlobCentroid.height-b.m_BlobCentroid.height)*(m_BlobCentroid.height-b.m_BlobCentroid.height));
	}
	
	
	
	public boolean contains(Dimension d)
	{
		return m_PointSet.contains(d.width+d.height*m_WidthTotal);
	}
	
	public int size()
	{
		return m_PixelCount;
	}
	
	public Dimension getDimension()
	{
		return m_BlobDimension;
	}
	
	public Dimension getCentroid()
	{
		return m_BlobCentroid;
	}
	
	public Dimension[] getBoundingPoints()
	{
		return new Dimension[]{m_BottomLeft,m_TopRight};
	}
	
	public Vector<Dimension> getDimensionPoints()
	{
		return m_ListOfDimensionPoints;
	}
	
	public Vector<Integer> getLinearPoints()
	{
		return m_ListOfLinearPoints;
	}
	
	public int getLinearPoint(Dimension d)
	{
		return d.width+m_WidthTotal*d.height;
	}
	//public Vector<Dimension> get
	
	public boolean isPointBelowBlob(Dimension d, int minDistance)
	{
		return m_BottomLeft.height-d.height-minDistance>=0;
	}
	
	public boolean isPointBelowBlob(Dimension d)
	{
		return isPointBelowBlob(d,1);
	}
	
	public boolean isPointAboveBlob(Dimension d, int minDistance)
	{
		return d.height-m_TopRight.height-minDistance>=0;
	}
	
	public boolean isPointAboveBlob(Dimension d)
	{
		return isPointAboveBlob(d,1);
	}
	
	public boolean isPointLeftOfBlob(Dimension d, int minDistance)
	{
		return m_BottomLeft.width-d.width-minDistance>=0;
	}
	
	public boolean isPointLeftOfBlob(Dimension d)
	{
		return isPointLeftOfBlob(d,1);
	}
	
	public boolean isPointRightOfBlob(Dimension d, int minDistance)
	{
		return d.width-m_TopRight.width-minDistance>=0;
	}
	
	public boolean isPointRightOfBlob(Dimension d)
	{
		return isPointRightOfBlob(d,1);
	}
	
	
	public Object clone()
	{
		BlobInfo bInfo = new BlobInfo();
		bInfo.m_BlobCentroid= (Dimension)m_BlobCentroid.clone();
		bInfo.m_PixelCount=m_PixelCount;
		bInfo.m_PointSet=(HashSet)m_PointSet.clone();
		bInfo.m_ListOfLinearPoints=(Vector)m_ListOfLinearPoints.clone();
		bInfo.m_ListOfDimensionPoints=(Vector)m_ListOfDimensionPoints.clone();
		bInfo.m_WidthTotal=m_WidthTotal;
		bInfo.m_HeightTotal=m_HeightTotal;
		bInfo.m_BlobDimension=(Dimension)m_BlobDimension.clone();
		bInfo.m_BottomLeft=(Dimension)m_BottomLeft.clone();
		bInfo.m_TopRight=(Dimension)m_TopRight.clone();
		return bInfo;
	}
	
	public void addAllPoints(BlobInfo inputBlob)
	{
		for (Dimension d: inputBlob.getDimensionPoints())
		{
			add(d);
		}
	}
	
	public Hashtable<String,Integer> getHashData()
	{
		Hashtable<String,Integer> data = new Hashtable();
		data.put("width", m_BlobDimension.width);
		data.put("height", m_BlobDimension.height);
		data.put("centroidX", m_BlobCentroid.width);
		data.put("centroidY", m_BlobCentroid.height);
		data.put("blobMass", m_PixelCount);
		return data;
	}
	
	

}
